package com.jesse.eclgy.plug.wrapper;

import com.jesse.eclgy.plug.enums.FieldType;
import com.jesse.eclgy.plug.util.ReflectionUtils;

import java.util.*;

/**
 * 条件包装器，生成的SQL。 不包含WHERE　关键字
 *
 * @Author: jesse
 * @Date: 2023/6/3 12:45
 */
public class ConditionWrapper implements IWrapper {

    private List<Object> params;
    private StringBuilder condition;

    /**
     * 构造
     */
    private ConditionWrapper()
    {
        this.params = new ArrayList<>();
        this.condition = new StringBuilder();
    }

    public static ConditionWrapper builder()
    {
        return new ConditionWrapper();
    }


    public ConditionWrapper and()
    {
        appendCondition(" AND ");
        return this;
    }

    public ConditionWrapper or()
    {
        appendCondition(" OR ");
        return this;
    }

    public ConditionWrapper condition(String condition)
    {
        this.condition.append(condition);
        return this;
    }

    /**
     * 拼接子查询
     * and .....
     * @param condition
     * @param childQuery
     * @return
     */
    public ConditionWrapper condition(String condition, QueryWrapper childQuery)
    {
        this.condition.append(condition);
        this.condition.append("(");
        this.condition.append(childQuery.getSql());
        this.condition.append(")");
        this.params.addAll(childQuery.getParams());
        return this;
    }

    public ConditionWrapper condition(Map<String, Object> conditionMap)
    {
        if (conditionMap.isEmpty())
        {
            return this;
        }
        StringJoiner stringJoiner = new StringJoiner(" AND ", " ", " ");
        conditionMap.forEach((k, v) -> {
            stringJoiner.add(k + "=?");
            this.params.add(v);
        });
        this.condition.append(stringJoiner);
        return this;
    }

    public ConditionWrapper eq(String field, Object value)
    {
        appendCondition(new StringJoiner("=").add(field).add("?"));
        this.params.add(value);
        return this;
    }

    public ConditionWrapper gt(String field, Object value)
    {
        appendCondition(new StringJoiner(" > ").add(field).add("?"));
        this.params.add(value);
        return this;
    }

    public ConditionWrapper gteq(String field, Object value)
    {
        appendCondition(new StringJoiner(" >= ").add(field).add("?"));
        this.params.add(value);
        return this;
    }

    public ConditionWrapper lt(String field, Object value)
    {
        appendCondition(new StringJoiner(" < ").add(field).add("?"));
        this.params.add(value);
        return this;
    }

    public ConditionWrapper lteq(String field, Object value)
    {
        appendCondition(new StringJoiner(" <= ").add(field).add("?"));
        this.params.add(value);
        return this;
    }

    public ConditionWrapper like(String field, Object value)
    {
        appendCondition(new StringJoiner(" LIKE ").add(field).add("?"));
        if (String.valueOf(value).startsWith("%") || String.valueOf(value).endsWith("%"))
        {
            this.params.add(value);
        } else
        {
            this.params.add("%" + value + "%");
        }
        return this;
    }

    public ConditionWrapper in(String field, Object... value)
    {
        StringJoiner sj = new StringJoiner(",", "(", ")");
        Arrays.stream(value).forEach(v -> sj.add(v instanceof String ? "'" + v + "'" : v.toString()));
        appendCondition(new StringJoiner(" IN ").add(field).add(sj.toString()));
        return this;
    }

    public ConditionWrapper andChildCondition(ConditionWrapper conditionWrapper)
    {
        this.and();
        this.childCondition(conditionWrapper);
        return this;
    }

    public ConditionWrapper orChildCondition(ConditionWrapper conditionWrapper)
    {
        this.or();
        this.childCondition(conditionWrapper);
        return this;
    }

    public ConditionWrapper childCondition(ConditionWrapper conditionWrapper)
    {
        StringJoiner sj = new StringJoiner(" ", "(", ")");
        sj.add(conditionWrapper.getSql());
        appendCondition(sj.toString());
        this.params.addAll(conditionWrapper.getParams());
        return this;
    }

    @Override
    public List<Object> getParams()
    {
        return this.params;
    }

    @Override
    public ConditionWrapper inject(Object obj)
    {
        this.condition(ReflectionUtils.getFieldMap(obj, FieldType.CONDITON));
        return this;
    }

    @Override
    public String getSql()
    {
        return this.condition.toString();
    }

    private void appendCondition(String condition)
    {
        this.condition.append(condition);
    }

    private void appendCondition(StringJoiner stringJoiner)
    {
        this.condition.append(stringJoiner);
    }



}
